/**********************************************************************************
 * Code license:  GNU General Public License v3                                   *
 * Main page:     https://code.google.com/p/library-cross-platform/               *
 * Issue tracker: https://code.google.com/p/library-cross-platform/issues/list    *
***********************************************************************************/

package library.file;

import java.nio.*;
import java.io.*;
import java.nio.channels.*;
import java.nio.charset.*;

public class AdoptedAsciiReader
{
  protected static final int   defaultBufferReaderSize   = 10 * FileConstant.MBYTE;

  private   int                itsCount;
  protected int                buffer_reader_size        = defaultBufferReaderSize;
  protected File               _file;
  protected FileInputStream    fis;
  protected FileChannel        fich;
  protected ByteBuffer         bb;
  protected int                nread;
  protected Charset            cs                        = Charset.forName("ASCII");
  protected CharBuffer         char_buffer;
  protected StringBuilder      str_buffer                = new StringBuilder(FileConstant.MBYTE);
  
  
  public AdoptedAsciiReader(File f) {
    _file = f;
    long file_size = _file.length();
    if(file_size < defaultBufferReaderSize)
      buffer_reader_size = (int)_file.length();
    else
      buffer_reader_size = defaultBufferReaderSize;
    
    itsCount = 0;
    try {
      _open();
    } catch(IOException ex) {
      ex.printStackTrace();
    };
  }
  
  protected void _open() throws IOException {
     fis = new FileInputStream(_file);
     fich = fis.getChannel();
     bb = ByteBuffer.allocateDirect((int) buffer_reader_size);
     bb.clear();
  }
  
  public void close() {
    try {
      fich.close();
      fis.close();
      bb = null;
      fich = null;
      fis = null;
    } catch (IOException unused) {};
  }
  
  public int read() throws IOException {
    int ret_value = 0;
    if(char_buffer == null || char_buffer.hasRemaining() == false) {
      if(_readCharBuffer() == -1) {
        char_buffer = null;
        return -1;
      }
    }
      
    if(char_buffer.hasRemaining())
      ret_value = char_buffer.get();
    else
      ret_value = -1;

    return ret_value;
  }
  
  protected int _readCharBuffer() throws IOException {
    char c;
    if(char_buffer == null)
      char_buffer = CharBuffer.allocate((int)buffer_reader_size);
    char_buffer.clear();
    
    if((nread = fich.read(bb)) == -1)
      return -1;
    bb.flip();
    while(bb.hasRemaining()) {
      c = (char)bb.get();
      char_buffer.append(c);
    }
    bb.clear();
    char_buffer.flip();
    return nread;
  }
  
  public int read(char[] cbuf, int off, int len) throws IOException {
    int read_count = 0;
    if((len + off) < cbuf.length)
     return -1;
    while((len + off) < cbuf.length) {
      if(char_buffer == null || char_buffer.hasRemaining() == false) {
        if(_readCharBuffer() == -1)
          return -1;
        else {
           while(char_buffer.hasRemaining() && (len + off) < cbuf.length) {
             cbuf[off++] = char_buffer.get();
             read_count ++;
           }
        }
      }
    }
    return read_count;
  }
  
  public String readLine() throws IOException {
   str_buffer.setLength(0);
   int c = read(); itsCount ++;
/** Read chars until EOL received (FL, CR or EOF) */
   while(c != 0x0A && c != 0x0D && c != -1) {
     str_buffer.append((char)c);
     c = read(); itsCount ++;
   }
/** If the latest symbol is \r then \n will be after that. Need to read too. */
   if(c == 0x0D) {
     c = read(); itsCount ++;
   }
   
/** If EOF - return NULL (EOF's should not be counted) */
   if(c == -1) {
    itsCount --;
    return null;
   }
   return str_buffer.toString();
  }
  
  public int getCharCount() {
    return itsCount;
  }
}
